#include <iostream>
#define DLL_EXPORT __declspec(dllexport)
#include <cppunit/BriefTestProgressListener.h>
#include <cppunit/CompilerOutputter.h>
#include <cppunit/TestPath.h>
#include <cppunit/TestFailure.h>
#include <cppunit/TestResult.h>
#include <cppunit/TestResultCollector.h>
#include <cppunit/TestRunner.h>
#include <cppunit/TextOutputter.h>
#include <cppunit/TextTestProgressListener.h>
#include <cppunit/XmlOutputter.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <cppunit/plugin/DynamicLibraryManagerException.h>
#include <cppunit/plugin/PlugInParameters.h>
#include <cppunit/plugin/PlugInManager.h>
#include <cppunit/plugin/TestPlugIn.h>
#include <cppunit/portability/Stream.h>
#include <string>
#include <assert.h>
#include "MyListener.h"
#include "CppUnitTestRunner.h"


extern "C"
{
	DLL_EXPORT bool RunAllTests(const char* dllPath);
	DLL_EXPORT CppUnitTestRunner* CreateTestRunner();
	DLL_EXPORT void DeleteTestRunner(CppUnitTestRunner* p_pTestRunner);
	DLL_EXPORT void LoadTests(CppUnitTestRunner* p_pTestRunner, const char* p_pszPluginPath);
	DLL_EXPORT void UnloadTests(CppUnitTestRunner* p_pTestRunner, const char* p_pszPluginPath);
	DLL_EXPORT bool RunTest(CppUnitTestRunner* p_pTestRunner, const char* p_pszTestPath);
	DLL_EXPORT CPPUNIT_NS::Test* GetTestRoot(CppUnitTestRunner* p_pTestRunner);
	DLL_EXPORT int GetNoOfChildTests(CPPUNIT_NS::Test* test);
	DLL_EXPORT CPPUNIT_NS::Test* GetTestChild(CPPUNIT_NS::Test* test, int index);
	DLL_EXPORT const char* GetTestName(CPPUNIT_NS::Test* test);
	DLL_EXPORT void DeleteStringBuffer(char* buffer);
}

using namespace std;
int levelCount = 0;

void dumpTestNames(const CPPUNIT_NS::Test* test)
{
	assert(test);
	std::cout << levelCount << " : " << test->getName() << endl;
	levelCount++;

	for(int i=0; i<test->getChildTestCount(); i++)
	{
		CPPUNIT_NS::Test* currentTest = test->getChildTestAt(i);
		CPPUNIT_NS::TestComposite* childtestComposite = dynamic_cast<CPPUNIT_NS::TestComposite*>(currentTest);

		if(childtestComposite != NULL)
			dumpTestNames(childtestComposite);
		else
			std::cout << levelCount << " : " << currentTest->getName() << std::endl;
	}

	levelCount--;
}

bool RunAllTests(const char* pluginPath)
{
	bool wasSuccessful = false;
	CPPUNIT_NS::PlugInManager plugInManager;
	CPPUNIT_NS::TestResult controller;
	CPPUNIT_NS::TestResultCollector result;
	controller.addListener( &result );

	MyListener myListener;
	controller.addListener( &myListener );

	/*CPPUNIT_NS::BriefTestProgressListener briefListener;
	controller.addListener( &briefListener );*/
	plugInManager.addListener( &controller );
	plugInManager.load(pluginPath, CPPUNIT_NS::PlugInParameters());


	CPPUNIT_NS::TestRunner runner;
	runner.addTest( CPPUNIT_NS::TestFactoryRegistry::getRegistry().makeTest() );

	//	Dumping all tests
	/*CPPUNIT_NS::TestComposite* testComposite = 
		dynamic_cast<CPPUNIT_NS::TestComposite*>(CPPUNIT_NS::TestFactoryRegistry::getRegistry().makeTest());

	dumpTestNames(testComposite);*/

	try
	{
		runner.run( controller, string("EmployeeTest"));
		wasSuccessful = result.wasSuccessful();
	}
	catch ( std::invalid_argument & )
	{
		CPPUNIT_NS::stdCOut()  <<  "Failed to resolve test path: "  
			<<  "\n";
	}

	plugInManager.removeListener( &controller );
	return wasSuccessful;
}

//	Exported methods
CppUnitTestRunner* CreateTestRunner()
{
	return new CppUnitTestRunner();
}

void DeleteTestRunner(CppUnitTestRunner* p_pTestRunner)
{
	delete p_pTestRunner;
}

void LoadTests(CppUnitTestRunner* p_pTestRunner, const char* p_pszPluginPath)
{
	p_pTestRunner->LoadTests(p_pszPluginPath);
}

void UnloadTests(CppUnitTestRunner* p_pTestRunner, const char* p_pszPluginPath)
{
	p_pTestRunner->UnloadTests(p_pszPluginPath);
}

bool RunTest(CppUnitTestRunner* p_pTestRunner, const char* p_pszTestPath)
{
	bool successful = p_pTestRunner->RunTest(p_pszTestPath);
	return successful;
}

CPPUNIT_NS::Test* GetTestRoot(CppUnitTestRunner* p_pTestRunner)
{
	return p_pTestRunner->GetTestRoot();
}

int GetNoOfChildTests(CPPUNIT_NS::Test* test)
{
	return test->getChildTestCount();
}

CPPUNIT_NS::Test* GetTestChild(CPPUNIT_NS::Test* test, int index)
{
	return test->getChildTestAt(index);
}

const char* GetTestName(CPPUNIT_NS::Test* test)
{
	std::string name = test->getName();
	char* c = new char[name.length() + 1];
	strcpy(c, name.c_str());
	c[name.length()] = '\0';
	return c;
}

void DeleteStringBuffer(char* buffer)
{
	delete [] buffer;
}